using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Text;
using System.Net;
using System.Xml;

namespace MossAccess
{
    /// <summary>
    /// Used to inject search queries to the MOSS search web service
    /// </summary>
    /// 
    public class MossQuery
    {
        #region Public Methods
        /// <summary>
        /// Perform a search query against a MOSS web service
        /// </summary>
        /// <param name="QueryRequest">The query request</param>
        /// <returns>QueryResult</returns>
        public QueryResponse PerformQuery(QueryRequest queryRequest)
        {
            // Create the query result
            QueryResponse returnQueryResponse = new QueryResponse();

            try
            {
                // Create a query service object
                QueryService.QueryService queryService = new QueryService.QueryService();

                // Set authentication credentials
                NetworkCredential networkCredential = CredentialCache.DefaultCredentials.GetCredential(new Uri(queryService.Url), "NTLM");
                queryService.Credentials = networkCredential;

                // Set the target, if appropriate
                if (string.IsNullOrEmpty(queryRequest.Target) == false)
                {
                    queryService.Url = queryRequest.Target;
                }

                // // Register with Web service
                // string registrationString = "<RegistrationRequest revision=\"1\" xmlns=\"urn:Microsoft.Search.Registration.Request\" action=\"NEW\"/>";
                //returnQueryResponse.XmlRegistrationResponse = queryService.Registration(registrationString);

                // Build an xml query string
                returnQueryResponse.XmlQueryRequest = queryRequest.ToString();

                // Execute the query and record the response
                returnQueryResponse.XmlQueryResponse = queryService.Query(returnQueryResponse.XmlQueryRequest);

                // Get the data set results
                DataSet dataSetResult = queryService.QueryEx(returnQueryResponse.XmlQueryRequest);

                // Set the various response data tables
                returnQueryResponse.DataTableQueryRelevantResults = SetReturnDataTable(dataSetResult, "RelevantResults");
                returnQueryResponse.DataTableQueryHighConfidenceResults = SetReturnDataTable(dataSetResult, "HighConfidenceResults");
                returnQueryResponse.DataTableQuerySpecialTermResults = SetReturnDataTable(dataSetResult, "SpecialTermResults");

                // Set control variables
                SetControlData(returnQueryResponse.DataTableQueryRelevantResults, returnQueryResponse);
            }
            catch (Exception exception)
            {
                throw new Exception("Unable to perform query", exception);
            }

            // Return the returnQueryResponse
            return (returnQueryResponse);
        }

        public SearchMetadata GetSearchMetaData()
        {
            SearchMetadata returnSearchMetaData = new SearchMetadata();

            try
            {
                // Create a query service object
                QueryService.QueryService queryService = new QueryService.QueryService();

                // Set authentication credentials
                NetworkCredential networkCredential = CredentialCache.DefaultCredentials.GetCredential(new Uri(queryService.Url), "NTLM");
                queryService.Credentials = networkCredential;

                // Get the search metadata
                DataSet searchMetadata = queryService.GetSearchMetadata();

                // Set the return tables
                returnSearchMetaData.Properties = searchMetadata.Tables["Properties"];
                returnSearchMetaData.Scopes = searchMetadata.Tables["Scopes"];

            }
            catch (Exception exception)
            {
                throw new Exception("Unable to get search metadata", exception);
            }

            // Return the search metadata
            return (returnSearchMetaData);

        }
        #endregion

        #region Private Helper Methods

        private void SetControlData(DataTable relevantResults, QueryResponse queryResponse)
        {
            string totalRows = (string)relevantResults.ExtendedProperties["TotalRows"];
            queryResponse.TotalAvailable = Convert.ToInt32(totalRows);
            queryResponse.Count = relevantResults.Rows.Count;
        }

        /// <summary>
        /// Returns a table from the dataset, if it is present
        /// </summary>
        /// <param name="dataSet">The data set</param>
        /// <param name="tableName">The name of the table</param>
        /// <returns></returns>
        private DataTable SetReturnDataTable(DataSet dataSet, string tableName)
        {
            // Check to see whether the data set as a table of the given name
            if (dataSet.Tables.Contains(tableName))
            {
                // If it has, return the table
                return (dataSet.Tables[tableName]);
            }
            else
            {
                // If it hasn't return null
                return (null);
            }
        }

        private void ListTables(DataSet dataSet)
        {
            foreach (DataTable table in dataSet.Tables)
            {
                System.Diagnostics.Trace.WriteLine("Name: " + table.TableName);

                // Print out the column names
                foreach (DataColumn column in table.Columns)
                {
                    System.Diagnostics.Trace.Write(column.ColumnName + "\t");
                }
                System.Diagnostics.Trace.WriteLine(string.Empty);

                // Print out the row values
                foreach (DataRow row in table.Rows)
                {
                    foreach (DataColumn column in table.Columns)
                    {
                        System.Diagnostics.Trace.Write(row[column].ToString() + "\t");
                    }
                    System.Diagnostics.Trace.WriteLine(string.Empty);
                }
                System.Diagnostics.Trace.WriteLine(string.Empty);
            }
        }
        #endregion
    }
}
